package zzz

import (
	"errors"
	"fmt"
	"github.com/nntaoli-project/goex"
	"github.com/patrickmn/go-cache"
	"log"
	"math"
	"quantization_trading/src/models"
	"quantization_trading/src/mycache"
	"quantization_trading/src/server/ws"
	"quantization_trading/src/util"
	"sync"
	"time"
)

type kline struct {
	high float64
	low float64
	close float64
}

type WildFluctuationStrategy struct {
	StrategyName string
	Status bool //策略是否启动
	Accounts map[string]models.Account

	Exchange string `json:"exchange"` //交易所
	ContractType string `json:"contract_type"` //合约类型
	Symbol string `json:"symbol"`  //交易对

	OpenWave	float64	//开仓波动率
	CloseWave	float64 //平仓波动率
	Amount	float64	//首次购买数量
	Interval	int64	//自定义k线间隔
	HoldOrder models.Order	//持有订单
	IntentOrder models.Order //委托订单

	// 价格管道
	PriceChan chan *goex.Trade
	close                  chan bool
	lck      *sync.Mutex
	PriceMap map[int64] *kline
	newTime  int64
	MyKline  kline
}

var (
    defaultWildFluctuationStrategy = WildFluctuationStrategy{
		Exchange: "binance",
		ContractType: "swap-usdt",
		Symbol: "sol_usdt",
		StrategyName: "default",
		OpenWave: 0.001,
		CloseWave: 0.02,
		Amount: 1,
		Interval: 5 * 60,
		Accounts: make(map[string]models.Account),
		close : make(chan bool, 1),
		PriceChan : make(chan *goex.Trade, 10),
		lck : new(sync.Mutex),
		PriceMap : make(map[int64] *kline),
		MyKline: kline{
			high: -math.MaxFloat64,
			low: math.MaxFloat64,
		},
	}

)

func NewWildFluctuationStrategy(strategy *WildFluctuationStrategy) WildFluctuationStrategy {
	var wfs WildFluctuationStrategy
	accounts := []models.Account{}
	if strategy == nil{
		wfs = defaultWildFluctuationStrategy
	}else {
		wfs = *strategy
	}
	key := fmt.Sprintf("%s_user", "hl")
	if x, found := mycache.AccountCache.Get(key); found {
		accounts = x.([]models.Account)
	}
	for _,ac :=range accounts {
		wfs.AddAccount(&ac)
	}
	mycache.StrategyCache.Set(wfs.StrategyName,wfs,cache.NoExpiration)
	return wfs
}

//添加用户
func (wfs *WildFluctuationStrategy)AddAccount(account *models.Account) error {
	if account == nil{
		return errors.New("用户不能为空")
	}
	wfs.Accounts[account.AccountName] = *account
	return nil
}

//删除用户
func (wfs *WildFluctuationStrategy)DelAccount(account *models.Account) error {
	if account == nil{
		return errors.New("用户不能为空")
	}
	delete(wfs.Accounts, account.AccountName)
	return nil
}

//启动策略
func (wfs *WildFluctuationStrategy)StartStrategy() int {
	var sub ws.SubscribePriceStruct
	key := fmt.Sprintf("%s_%s_%s_price", wfs.Exchange, wfs.ContractType, wfs.Symbol)
	if x, found := mycache.PriceCache.Get(key); found {
		sub = x.(ws.SubscribePriceStruct)
		sub.TradeCallback(func(trade *goex.Trade, contract string) {
			wfs.PriceChan <- trade

		})
		wfs.Status = true
		go wfs.HandlePrice()
		// 需要更新缓存
		mycache.StrategyCache.Set(wfs.StrategyName,*wfs,cache.NoExpiration)
		return util.START_SUSSESS_STRATEGY
	}else {
		log.Println("没有订阅该数据")
		return util.NOT_SUB_PRICE
	}
}

// tudo 停止策略
func (wfs *WildFluctuationStrategy)StopStrategy() error {
	// 删除订阅价格
	var sub ws.SubscribePriceStruct
	wfs.Status =false
	key := fmt.Sprintf("%s_%s_%s_price", wfs.Exchange, wfs.ContractType, wfs.Symbol)
	if x, found := mycache.PriceCache.Get(key); found {
		sub = x.(ws.SubscribePriceStruct)
		sub.TradeCallback(ws.DefaultCallBack)
		wfs.close <- true
		// 需要更新缓存
		mycache.StrategyCache.Set(wfs.StrategyName,*wfs,cache.NoExpiration)
		return nil
	}else {
		wfs.close <- true
		//close(wfs.close)
		// 需要更新缓存
		mycache.StrategyCache.Set(wfs.StrategyName,*wfs,cache.NoExpiration)
		return errors.New("没有订阅该数据")
	}
}

//处理价格
func (wfs *WildFluctuationStrategy)HandlePrice()  {
	t := time.NewTicker(time.Second * 1)
	defer t.Stop()
	for {
		select {
		case <-wfs.close:
			log.Println("退出价格处理")
			return
		case <-t.C:
			wfs.lck.Lock()
			temp_max := -math.MaxFloat64
			temp_min := math.MaxFloat64
			for k,v := range wfs.PriceMap {
				if k >= wfs.newTime - wfs.Interval{
					if v.low  < temp_min {
						temp_min = v.low
					}
					if v.high > temp_max {
						temp_max = v.high
					}
				}else {
					delete(wfs.PriceMap,k)
				}
			}
			// 当前的最大值、最小值、最新值
			wfs.MyKline.high = temp_max
			wfs.MyKline.low = temp_min
			wfs.lck.Unlock()
		case price := <-wfs.PriceChan:
			wfs.lck.Lock()
			wfs.newTime = price.Date /1000
			if key, fund := wfs.PriceMap[wfs.newTime]; fund {
				var k kline
				k.low = math.MaxFloat64
				if price.Price < key.low {
					k.low = price.Price
				}else {
					k.low = key.low
				}
				if price.Price > key.high {
					k.high = price.Price
				}else {
					k.high = key.high
				}
				k.close = price.Price
				wfs.PriceMap[wfs.newTime] = &k
			}else {
				wfs.PriceMap[wfs.newTime] = &kline{
					high:  price.Price,
					low:  price.Price,
					close:  price.Price,
				}
			}
			wfs.MyKline.close = price.Price
			if wfs.MyKline.high < price.Price{
				wfs.MyKline.high = price.Price
			}
			if wfs.MyKline.low > price.Price{
				wfs.MyKline.low = price.Price
			}
			wfs.WaveOrder()
			wfs.lck.Unlock()
		}
	}
}

//Wave
func (wfs *WildFluctuationStrategy)WaveOrder(){
	//log.Printf("当前涨幅:%f,当前跌幅:%f",util.Volatility(wfs.MyKline.close,wfs.MyKline.low),util.Volatility(wfs.MyKline.high , wfs.MyKline.close))
	if util.Volatility(wfs.MyKline.high , wfs.MyKline.close) > wfs.OpenWave{
		// 爆跌
		log.Println("爆跌")
		wfs.initKline()
		return
	}else if util.Volatility(wfs.MyKline.close,wfs.MyKline.low) > wfs.OpenWave{
		// 爆涨
		log.Println("爆涨")
		wfs.initKline()
		return
	}
}

func (wfs *WildFluctuationStrategy)initKline()  {
	wfs.MyKline = kline{
		high: -math.MaxFloat64,
		low: math.MaxFloat64,
	}
	wfs.PriceMap = make(map[int64] *kline)
}